﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using Microsoft.AspNet.Routing;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using Sino.CapacityCloud.Infrastructure.Features;
using Sino.WebApi.Framework.Abstractions.Cryptography;

namespace Sino.CapacityCloud.Infrastructure.Midwares
{

    public class TokenAuthenticationMiddleware
    {

        private readonly RequestDelegate _next;
        private readonly ILogger _logger;
        private readonly ITokenGenerator _tokenGenerator;

        public TokenAuthenticationMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, ITokenGenerator tokenGenerator)
        {
            this._next = next;
            this._logger = loggerFactory.CreateLogger<TokenAuthenticationMiddleware>();
            this._tokenGenerator = tokenGenerator;
        }

        public async Task Invoke(HttpContext context)
        {
            // If the client send the request with a token, then we check it and store it if it is valid.
            if (context.Request.Headers.ContainsKey("Token"))
            {
                var token = context.Request.Headers["Token"].ToString();
                this._logger.LogInformation($"Requesting {context.Request.Path} with token {token}.");
                if (!this._tokenGenerator.ValidateToken(token))
                {
                    this._logger.LogError($"The request to {context.Request.Path} has been rejected because the given token {token} is expired.");
                    context.Response.Clear();
                    context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                    return;
                }
                context.Features[typeof(ITokenFeature)] = new TokenFeature(token);
            }
            await _next.Invoke(context);
        }

    }

    public static class TokenAuthenticationMiddlewareExtensions
    {

        public static IApplicationBuilder UseTokenAuthenticationMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<TokenAuthenticationMiddleware>();
        }

    }

}